package com.example.socket.codec.protobuf;

import com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * @author frank
 * @date 2020-03-10 6:05 下午
 * @desc
 **/
public class GeneratedProto {

    //生成的proto文件存放位置
    private static final String dir;
    /** 默认资源匹配符 */
    protected static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
    /**
     *扫描的包
     **/
    private static String[] packages = {
            "com.lsa.game.pojo"
    };

    static {
        ProtobufIDLGenerator.BASE_PKG = "com.lsa.game.pojo.";
        dir = getOutPath();
        clearDir();
    }

    private static void clearDir() {
        try {
            FileUtils.cleanDirectory(new File(dir));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取proto文件输出目录
     */
    private static String getOutPath() {
        File file1 = new File("");
        String projectPath = file1.getAbsolutePath();
        return projectPath + File.separator + "pojo" + File.separator +
                "src" + File.separator + "main" +
                File.separator + "resources" + File.separator + "game-protoc" + File.separator + "protos";
    }

    /** 资源搜索分析器，由它来负责检索 */
    private static ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    /** 类的元数据读取器，由它来负责读取类上的注释信息 */
    private static MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Collection<Resource> resources = findResource();
        Set<Class<?>> cachedTypes = new HashSet<>();
        Set<Class<?>> cachedEnumTypes = new HashSet<>();
        Map<String, ProtoFile> protoFiles = new HashMap<>();
        for (Resource resource : resources) {
            if (!resource.isReadable()) {
                continue; // 不可读资源，忽略
            }
            // 判断是否有 ProtoBufClass 注释
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
            AnnotationMetadata annoData = metadataReader.getAnnotationMetadata();
            if (!annoData.hasAnnotation(ProtobufClass.class.getName())) {
                continue; // 不是要处理的资源，忽略
            }
            ClassMetadata clzMeta = metadataReader.getClassMetadata();
            Class<?> clz = Class.forName(clzMeta.getClassName());
            ProtobufIDLGenerator.getIDL(clz, cachedTypes, cachedEnumTypes, protoFiles);
        }
        for (ProtoFile protoFile : protoFiles.values()) {

            File file = new File(dir, protoFile.getFileName());
            try (FileWriter writer = new FileWriter(file)) {
//                if(!useJavaPack){
//                    writer.write("package main;\n");
//                }else{
//                    writer.write("package " + protoFile.getPck() + ";\n");
//                }
                writer.write(protoFile.getHeader().toString());
                writer.write("package main;\n");
                writer.write("\n");
                for (String imp : protoFile.getImports()) {
                    writer.write("import public \"" + imp + "\";\n");
                }
                writer.write("option java_package = \"" + protoFile.getPkg() + "\";");
                writer.write("\n\n");
                writer.write(protoFile.getBody().toString());
                writer.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static Collection<Resource> findResource() throws IOException {
        Collection<Resource> resources = new HashSet<>();
        for (String name : packages) {
            String path = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(name) + "/"
                    + DEFAULT_RESOURCE_PATTERN;
            Resource[] tmp = resourcePatternResolver.getResources(path);
            Collections.addAll(resources, tmp);
        }
        return resources;
    }

    private static String resolveBasePackage(String basePackage) {
        return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
    }

}
